home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODFDev / ODF / Found / FWExcLib / Include / FWExcImp.h < prev    next >
Encoding:
Text File  |  1996-08-16  |  10.1 KB  |  255 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                FWExcImp.h
  4. //    Release Version:    $ ODF 1 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. //========================================================================================
  11. //    THEORY OF OPERATION
  12. //
  13. //    This subsystem provides an emulation for C++ exception handling for compilers that
  14. //    do not yet support exceptions.
  15. //
  16. //    When an exception is thrown, the stack is unwound to the first enclosing try/catch 
  17. //    block.  Automatic (stack) objects are destroyed during stack unwinding.  Exceptions
  18. //    thrown during the construction of either an automatic or a dynamic (heap) object will
  19. //    result in the fully constructed subobjects of the partially constructed object
  20. //    being destroyed.
  21. //
  22. //    To obtain this behavior with exception handling emulation, the programmer must do
  23. //    extra work:
  24. //
  25. //        1) Classes which are to be destroyed during unwinding must be "registered"
  26. //        as auto-destruct classes, using the FW_DECLARE_AUTO and FW_DEFINE_AUTO
  27. //        macros 
  28. //
  29. //        2) The destructor and every constructor of auto-destruct classes must invoke 
  30. //        the FW_START_DESTRUCTOR and FW_END_CONSTRUCTOR macros (respectively).
  31. //
  32. //        3) Auto-destruct objects allocated on the heap must be allocated using the
  33. //        FW_NEW macro instead of using a plain new expression.
  34. //
  35. //    For the emulation to work, the code executed by the FW_END_CONSTRUCTOR and
  36. //    FW_START_DESTRUCTOR macros must determine the storage class of the object being
  37. //    constructed/destructed.  There are three possibilities: 1) automatic, 2) static, and
  38. //    3) dynamic.
  39.  
  40. //    Automatic objects must be tracked by the exception emulation.  
  41. //    Determining if the address of an object is on the stack is platform dependent but
  42. //    generally easy to do. We currently assume that it is possible to obtain a value
  43. //    for the stack base when the exception system in initialized, and store this value
  44. //    in the exception globals.  Care must be taken in a threaded environment with
  45. //    multiple stacks.  The stack top is determined by simply calling a function that
  46. //    returns the address of a local variable.
  47. //
  48. //    Static objects need not be tracked by the exception emulation, so
  49. //    the FW_END_CONSTRUCTOR and FW_START_DESTRUCTOR macros should act as no-ops.
  50. //    Unfortunately, there is no easy/portable way to determine if an address is located
  51. //    in the static data area.  We attempt to determine if the object is in static data
  52. //    via the process of elimination.  If the object is neither automatic or dynamic, then
  53. //    it is presumed to be static.  Unfortunately, this process of elimination gives incorrect
  54. //    results when programmer makes a particular mistake.  The mistake is relatively easy to
  55. //  make, and cannot be detected at compile time.  The mistake is made when a programmer
  56. //    creates a class that is not declared to be auto-destruct, but embeds an auto-destruct
  57. //    member object (by value) in the class.  When such a class is allocated in the heap
  58. //    via a new expression.
  59. //
  60. //    Dynamic auto-destruct objects must be allocated via the FW_NEW macro.  The FW_NEW
  61. //    macro invokes a special overloaded variant of operator new, and this variant registers
  62. //    the address range of the object being dynamically constructed.  This makes it
  63. //    relatively easy to determine if an address is that of an object (or subobject)
  64. //    currently being dynamically constructed.
  65. //
  66. //    There are several weaknesses with this mechanism for determining the storage class
  67. //    of an object.
  68. //
  69. //    First, if a class has member objects that are autodestruct objects,
  70. //    but the class itself is not autodestruct, then if it is allocated dynamically the
  71. //    member objects will not appear to be dynamic objects.  They are correctly rejected
  72. //    as automatic objects, so they are incorrectly classified as static objects, and the
  73. //    emulation incorrectly decides they need not be tracked.  The debug version of the
  74. //    emulation detects this problem and issues a warning.  Unfortunately, the warning
  75. //    might be issued for bonafide static objects, described next.
  76. //
  77. //    Second, any object which is not within a try-block context is assumed to be static.
  78. //    This assumption will always be valid in an application that does not dynamically
  79. //    load shared libraries at runtime.  (Not true! What about compilers/runtimes that
  80. //    delay construction of static objects until the first function call in a translation
  81. //    unit?)
  82. //
  83. //========================================================================================
  84.  
  85. #ifndef FWEXCIMP_H
  86. #define FWEXCIMP_H
  87.  
  88. #ifndef FWENVDEF_H
  89. #include "FWEnvDef.h"
  90. #endif
  91.  
  92. #ifndef SLPRIMEM_H
  93. #include "SLPriMem.h"
  94. #endif
  95.  
  96. #ifndef FWCLAIMP_H
  97. #include "FWClaImp.h"
  98. #endif
  99.  
  100. #include <setjmp.h>
  101.  
  102. #if defined(FW_BUILD_MAC) && !defined(__TYPES__)
  103. #include <Types.h>
  104. #endif
  105.  
  106. //========================================================================================
  107. // Forward Declarations
  108. //========================================================================================
  109.  
  110. FW_EXTERN_C_BEGIN
  111.  
  112. struct FW_SPrivTryBlockContext;
  113. struct FW_SPrivWatcher;
  114. struct FW_SPrivDeleteElem;
  115. struct FW_SPrivExceptionInfo;
  116.  
  117. typedef void (*FW_PrivDestroyProc)(void* self);
  118. typedef void (*FW_PrivDeleteProc)(void* self);
  119. typedef void (*FW_PrivCloneProc)(void* source, void* destination, size_t destSize);
  120. typedef void (*FW_PrivLongJumpProc)(jmp_buf,int);
  121.  
  122. #ifdef FW_DEBUG
  123.     void FW_AutoConstructed(void* object, size_t size, FW_PrivDestroyProc destroyer, char* name);
  124.     void FW_AutoDestructed(void* object, FW_PrivDestroyProc destroyer, char* name);
  125. #else
  126.     void FW_AutoConstructed(void* object, size_t size, FW_PrivDestroyProc destroyer);
  127.     void FW_AutoDestructed(void* object);
  128. #endif
  129.  
  130. void FW_PrivCaughtException(void* exception, size_t size, FW_SClassInfoPtr itsClass, FW_PrivDestroyProc itsDestroyer, FW_PrivCloneProc itsCloner);
  131. void FW_PrivCaughtReferenceException();
  132. void FW_PrivCaughtNoInstanceException();
  133. void FW_PrivCaughtEverythingException();
  134. void FW_PrivKeepThrowing();
  135. void FW_PrivCatchCleanup();
  136. void FW_PrivThrow(void* exception, size_t size, FW_SClassInfoPtr itsClass, FW_PrivDestroyProc itsDestroyer, FW_PrivCloneProc itsCloner);
  137. void FW_PrivThrowSame();
  138.  
  139. FW_Boolean FW_PrivCanCatchThisException(FW_SClassInfoPtr targetClass);
  140.  
  141. void FW_PrivTryBlockContext_Init(FW_SPrivTryBlockContext *self, jmp_buf buffer, FW_PrivLongJumpProc jumpProc);
  142. void FW_PrivTryBlockContext_Destroy(void *self);
  143. FW_SPrivTryBlockContext* FW_PrivTryBlockContext_MakeCurrent(FW_SPrivTryBlockContext* context);
  144.  
  145. void FW_PrivWatcher_Init(FW_SPrivWatcher* self, FW_PrivDeleteProc deleter);
  146. void* FW_PrivWatcher_Pop();
  147. void FW_PrivWatcher_Destroy(void* self);
  148. void* FW_PrivWatcher_New(void*p, size_t size, FW_SPrivWatcher* self);
  149.  
  150. void* FW_PrivGetThrownException();
  151.  
  152. //========================================================================================
  153. // volatile kludge
  154. //========================================================================================
  155.  
  156. // The FW_VOLATILE macro is used to workaround a problem that can happen with
  157. // setjmp/longjmp when variables are placed in registers. The macro takes the address
  158. // of the variable in an attempt to convince the compiler to not place the variable in
  159. // a register.  However, the result is not used, the compiler is free to eliminate the
  160. // expression, and then notice that the variable can be placed in register after all.
  161. // So, we take the address and place the result in this global.
  162.  
  163. extern void* FW_gPrivVolatileKludge;
  164.  
  165. //========================================================================================
  166. // struct FW_SPrivExceptionInfo
  167. //========================================================================================
  168.  
  169. struct FW_SPrivExceptionInfo
  170. {
  171.     void*                     fAddress;
  172.     size_t                    fSize;
  173.     FW_SClassInfoPtr        fClass;
  174.     FW_PrivDestroyProc         fDestroyer;
  175.     FW_PrivCloneProc         fCloner;
  176. };
  177.  
  178. //========================================================================================
  179. // struct FW_SPrivDeleteElem
  180. //========================================================================================
  181.  
  182. struct FW_SPrivDeleteElem
  183. {
  184.     void*                 fObject;
  185.     FW_PrivDestroyProc     fDestroyer;
  186. #ifdef FW_DEBUG
  187.     char*                fName;
  188.     FW_Boolean            fHeapAllocated;
  189. #endif
  190. };
  191.  
  192. //========================================================================================
  193. // struct FW_SPrivWatcher
  194. //========================================================================================
  195.  
  196. struct FW_SPrivWatcher
  197. {
  198.     FW_SPrivWatcher*    fNext;
  199.     void*                fObject;
  200.     void*                fLimit;
  201.     FW_PrivDeleteProc    fDeleter;
  202. #ifdef FW_DEBUG
  203.     long                fDeleteElems;
  204. #endif
  205. };
  206.  
  207. //========================================================================================
  208. // struct FW_SPrivTryBlockContext
  209. //========================================================================================
  210.  
  211. struct FW_SPrivTryBlockContext
  212. {
  213.     FW_SPrivTryBlockContext*    fPriorContext;
  214.     long                         fDeleteStackLevel;
  215.     jmp_buf*                    fJumpBuffer;
  216.     FW_PrivLongJumpProc            fJumpProc;
  217.     void*                        fPriorStackBase;
  218.     void*                        fPriorProcessBase;
  219. };
  220.  
  221. //========================================================================================
  222. // Design Notes
  223. //========================================================================================
  224.  
  225. /*
  226.  
  227. At construction time:
  228.     If stack or current heap object, Push DeleteElem on stack
  229.  
  230. At end of FW_NEW
  231.     Walk DeleteStack, removing entries for this object
  232.  
  233. At destruction time:
  234.     if the object is a stack based object, remove entry from DeleteStack
  235.  
  236. At stack-unwind time
  237.     Delete each elem on delete stack
  238.  
  239. At end of try-block scope
  240.     Verify delete stack is back to initial state
  241.  
  242. Note: the above approach assumes a try-way distinction for storage class of objects.
  243. Objects may be curent-heap, stack, or other.  Current-heap objects are objects currently
  244. being allocated via FW_NEW.  There is effectively a stack of such objects, in case
  245. the constructor of an object being allocated with FW_NEW calls FW_NEW to allocate
  246. another object.  The current-heap object is the top element of this stack.  The other
  247. category thus includes static objects and heap based objects other than the current-heap
  248. object.
  249.  
  250. */
  251.  
  252. FW_EXTERN_C_END
  253.  
  254. #endif
  255.